package com.matrix.order.infrastructure.message;

import com.matrix.api.product.ProductApi;
import com.matrix.common.constant.RocketMQConstants;
import com.matrix.common.enums.OrderStatusEnum;
import com.matrix.order.domain.model.Order;
import com.matrix.order.domain.model.OrderItem;
import com.matrix.order.domain.repository.OrderRepository;
import com.matrix.order.infrastructure.gateway.acl.ImAcl;
import com.matrix.order.infrastructure.gateway.acl.MerchantAcl;
import com.matrix.order.infrastructure.gateway.acl.PaymentAcl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcException;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 有点甜
 * @since 2025/8/5
 */
@Slf4j
@Component
@RocketMQMessageListener(
        topic = RocketMQConstants.ORDER_CREATION_TOPIC,
        consumerGroup = RocketMQConstants.ORDER_CREATION_CONSUMER_GROUP
)
@RequiredArgsConstructor
public class OrderSagaOrchestrator implements RocketMQListener<Map<String, Object>> {

    private final OrderRepository orderRepository;
    private final PaymentAcl paymentAcl;
    private final MerchantAcl merchantAcl;
    private final ImAcl imAcl;

    @DubboReference(check = false)
    private ProductApi productApi;

    @Override
    @Transactional
    public void onMessage(Map<String, Object> messagePayload) {
        String orderNo = (String) messagePayload.get("orderNo");
        Long userId = ((Number) messagePayload.get("userId")).longValue();

        log.info("SAGA: 开始处理订单创建流程, OrderNo: {}", orderNo);

        Order order = orderRepository.findByOrderNo(orderNo)
                .orElseThrow(() -> new IllegalStateException("SAGA错误：找不到预创建的订单 " + orderNo));

        if (order.getStatus() != OrderStatusEnum.PROCESSING) {
            log.warn("SAGA: 订单 {} 状态为 {}, 非处理中，跳过重复消费", orderNo, order.getStatus());
            return;
        }

        Map<Long, Integer> stockDeductionMap = order.getItems().stream()
                .collect(Collectors.toMap(OrderItem::getProductId, OrderItem::getQuantity, Integer::sum));

        try {
            if (!CollectionUtils.isEmpty(stockDeductionMap)) {
                log.info("SAGA: 步骤1 - 扣减库存, OrderNo: {}", orderNo);
                productApi.deductStock(stockDeductionMap);
            }

            log.info("SAGA: 步骤2 - 占用桌位, OrderNo: {}", orderNo);
            merchantAcl.occupyTable(order.getShopId(), order.getAreaSeat(), order.getId());

            order.setStatus(OrderStatusEnum.PENDING_PAYMENT);
            orderRepository.save(order);
            log.info("SAGA: 订单 {} 所有步骤成功，状态更新为待支付", orderNo);

            String qrCodeUrl = paymentAcl.requestPayment(order);

            Map<String, Object> pushPayload = Map.of(
                    "type", "ORDER_CREATED_SUCCESS",
                    "orderNo", order.getOrderNo(),
                    "qrCodeUrl", qrCodeUrl,
                    "totalAmount", order.getActualAmount()
            );
            imAcl.sendOrderCreationResult(userId, pushPayload);

        } catch (Exception e) {
            log.error("SAGA: 订单 {} 处理失败，开始执行补偿流程. 失败原因: {}", orderNo, e.getMessage());

            order.setStatus(OrderStatusEnum.CREATE_FAILED);
            order.setRemark("下单失败: " + e.getMessage());
            orderRepository.save(order);

            if (!CollectionUtils.isEmpty(stockDeductionMap)) {
                try {
                    productApi.increaseStock(stockDeductionMap);
                    log.info("SAGA补偿: 成功返还订单 {} 的库存", orderNo);
                } catch (RpcException rpcEx) {
                    log.error("SAGA补偿失败：返还订单 {} 库存时发生RPC异常", orderNo, rpcEx);
                }
            }

            Map<String, Object> pushPayload = Map.of(
                    "type", "ORDER_CREATED_FAILED",
                    "orderNo", orderNo,
                    "reason", e.getMessage()
            );
            imAcl.sendOrderCreationResult(userId, pushPayload);

            throw new RuntimeException("SAGA流程失败，已执行补偿", e);
        }
    }
}
